package com.gr.experimental.model.impl.distr.operations;

import java.lang.reflect.Method;
import java.util.Arrays;

import com.gr.experimental.model.impl.distr.Context;
import com.gr.experimental.model.impl.distr.ContextImpl;

public class MethodFunctionAdapter implements Function {
	
	Method method;
	boolean contextDependent;
	
	public MethodFunctionAdapter(Method method) {
		this.method = method;
		if (method.getParameterTypes().length > 0 
				&& Context.class.isAssignableFrom(method.getParameterTypes()[0])) {
					// we assume the context dependent method
					contextDependent = true;
				}
	}

	public String getName() {
		return method.getName();
	}

	public Class<?> getReturnType() {
		return method.getReturnType();
	}

	public Class<?>[] getParameterTypes() {
		Class<?>[] parameterTypes = method.getParameterTypes();
		if (contextDependent) {
			return Arrays.copyOfRange(parameterTypes, 1, parameterTypes.length);
		} else {
			return parameterTypes;
		}
	}

	@Override
	public Object invoke(Context ctx, Object[] parameters) throws FunctionCallException {
		try {
			if (isContextDependent() == true) {
				Object[] params2 = new Object[parameters.length + 1];
				params2[0] = ctx;
				for(int i=0; i< parameters.length; i++) {
					params2[i+1] = parameters[i];
				}
				parameters = params2;
			}
			return method.invoke(null, parameters);
		} catch(Exception ex) {
			throw new FunctionCallException("Error calling " + this.getName(), ex);
		}
	}

	@Override
	public boolean isContextDependent() {
		return contextDependent;
	}
	
	
}
